home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c / 190 < prev    next >
Internet Message Format  |  1996-08-06  |  14KB

  1. Path: solon.com!not-for-mail
  2. From: seebs@solutions.solon.com (Peter Seebach)
  3. Newsgroups: comp.lang.c.moderated,comp.lang.c,comp.std.c
  4. Subject: Re: Perhaps it's time the C community *did* something about bad books.
  5. Date: 25 Jan 1996 21:06:23 -0600
  6. Organization: Usenet Fact Police (Undercover)
  7. Approved: seebs
  8. Message-ID: <4e9gff$9n9@solutions.solon.com>
  9. References: <4e07lv$adu@solutions.solon.com> <4e5ooa$6b5@solutions.solon.com> <4e9f08$9br@solutions.solon.com>
  10. NNTP-Posting-Host: solutions.solon.com
  11.  
  12. In article <4e9f08$9br@solutions.solon.com>,
  13. Scott McMahan - Softbase Systems <softbase@mercury.interpath.com> wrote:
  14. >Not exactly. This is actually the review of the ANSI C standard.
  15. >The "review" errs on the side of being way too critical, and I've
  16. >seen it being debunked in part, but the parts that are debunked
  17. >never seem to be posted with the review anywhere. It's one of those
  18. >things that will endure forever.
  19.  
  20. Well, I went through it, and I saw nothing in it that was incorrect.
  21. I have the annotated standard, and it's pretty poorly annotated, IMHO.
  22.  
  23. >I did not see the post that listed errors in C: TCR. I'm interested
  24. >in reading it.
  25.  
  26. I didn't list them, I just said there were some.  It's about 8k/250
  27. lines, and it is pathetically far from complete.  In a letter to the
  28. editor at O-MGH, I mentioned several types of errors, so I found about
  29. 2-5 examples of each.  It took about 45 minutes, including skimming
  30. trying to find an offensively bad misstatement of how precedence
  31. works, which claims that
  32.     x = *p * (*p++);
  33. is legal.  (And not even because of the parens, but rather, because
  34. it's on the right.  Despite the correct statement about OOE earlier.)
  35.  
  36. >I agree that we should all make Osborne aware of all the errors in
  37. >Mr. Schildt's book so that he can make them better in future
  38. >editions. I was very disappointed in the 3rd Ed. compared to 
  39. >the 2nd.
  40.  
  41. He corrected at least one error; on or about page 53, the 2nd edition
  42. had "i <> 1" and the 3rd has "i != 1".
  43.  
  44. >On the other hand,
  45. >the third edition seems to have been released in extreme secrecy since I
  46. >learned about it only though a McGraw-Hill book-of-the-month club ad.
  47.  
  48. I agree; I only saw it last week in a bookstore for the first time.
  49.  
  50. >What's new?  The third edition is surprisingly unchanged. Instead of
  51. >taking the chance to reflect on which chapters he has written in his
  52. >almost 10 years of writing on C and picking the ones that would be most
  53. >useful to an ANSI C programmer, Schildt has instead placed chapters that
  54. >have little to do with a complete reference, including a tacky
  55. >self-promotion.
  56.  
  57. This is sadly true; a large number of obvious errors have survived.
  58.  
  59. Some are simply utterly stupid; the claim that you must use feof() to
  60. detect EOF on a binary file, since "EOF is an integer".  (Just like
  61. the ones returned by getchar(), which spends the entire book being
  62. returned into a char.)  I will not insult the intelligence of the
  63. reader by explaining this, suffice it to say I nearly fell out of
  64. my chair laughing at it.
  65.  
  66. >Unless Schildt starts trying to find what people want and starts
  67. >remembering why he wrote C:  The Complete Reference in the first place,
  68. >he and Osborne are going to have a hard time selling books with ads for
  69. >other books instead of content and using Schildt's name.  Schildt is
  70. >already known as a schmuck among real C programmers, deservedly or not,
  71. >and pretty soon everyone will be calling him the "recognized authority"
  72. >on self-promotion and hot air. Either Schildt or McGraw-Hill appears to
  73. >be damaging Schildt's already very shakey reputation beyond repair for
  74. >small short-term gain. I don't know why, is Osborne in some kind of
  75. >financial trouble? They should be trying to build a reputation for
  76. >quality.
  77.  
  78. *sigh*
  79.  
  80. A minor nit; he lists quicksort as generally the best sort known.
  81.  
  82. I have written the publisher a list (enclosed at the bottom of this
  83. post) of errors, and pointed out that this is really bad.  The editor
  84. I corresponded with (scottr@crl.com) said he'd run these by Herb to
  85. see if Schildt would appreciate a bit of technical editing.
  86.  
  87. I have been informed that they are no longer using the technical editor
  88. who was involved with this book, which really doesn't explain how
  89. this garbage survived 3 editions.
  90.  
  91. >Unfortunately for me, I will probably never order another edition of
  92. >this book, unless the concerns raised here are directly addressed.  I'm
  93. >very disenchanted with this book, and will look elsewhere for my
  94. >reference material.
  95.  
  96. I would never have gotten it if I weren't planning to offer the publisher
  97. "reasonable" rates on the technical editing the book desperately needs.
  98. Feel free to write the editor with comments, positive or negative,
  99. about my ability to improve on this work.  (Or me, for that matter.)
  100.  
  101. Enclosed please find the (mildly vitriolic in places) comments I have
  102. on a representative set of examples.  I am far from exhasting what I
  103. saw; I just wanted a good representative set.
  104.  
  105. Newbies to C:  Take the time to read through these, especially if you
  106. have the book.  Some of these errors could cost you hours or days of
  107. trying to figure out a problem.
  108.  
  109. ---
  110.  
  111. I am not including "bad style", but there are a few of those (gets is
  112. strongly depracated, and many programs don't output the last newline,
  113. probably because MS-DOS prints an extra one before the prompt.)
  114.  
  115. Please pardon typos, and even the possible errors; I have not taken the time
  116. to verify a couple of things.  For a serious, aimed-at-publication effort,
  117. I would, of course, take the time to bring the questionable points to the
  118. attention of people in comp.std.c, or otherwise cross-reference the work.
  119. As is, I'm just using memory and the Standard to compare.
  120.  
  121. Flat contradictions of ANSI's standard.
  122.  
  123.     Page 163
  124.  
  125.         "You may also declare main() as void if it does
  126.          not return a value."
  127.  
  128.     Specifically untrue.  ANSI mandates two declarations for main, and
  129.     says that main may have declarations compatible with those.  Both
  130.     return int.
  131.  
  132.     Page 434
  133.  
  134.         "free() must only be called with a pointer that was
  135.          previously allocated with one of the dynamic allocation
  136.          system's functions (either malloc(), realloc(), or
  137.          calloc())."
  138.  
  139.     Also specifically untrue.  ANSI states that free(NULL) is legal and
  140.     has no effect.  (Also note that it must be called with a pointer
  141.     *to space previously allocated*, not with a pointer previously
  142.     allocated, and that the pointer must not have been already freed
  143.     or passed to realloc().)
  144.  
  145.     Page 314
  146.  
  147.         "However, since EOF is a valid integer value, you must use
  148.          feof() to check for end-of-file when working with binary
  149.          files."
  150.  
  151.     Not merely a little bit untrue, but utterly wrong, and specifically
  152.     missing the point of the rule (correctly stated) about returning
  153.     the char as "unsigned char converted to int" (actually stated
  154.     in the standard in 7.9.7.1, under fgetc()).
  155.  
  156.     Since EOF is a *NEGATIVE* integral constant, it can *NEVER* compare
  157.     equal to *ANY* unsigned char.  When you are reading from a binary
  158.     file, the values you get will *never* compare equal to EOF, until
  159.     getchar() returns EOF because the file is empty.
  160.  
  161.     This correlates with a mistake made in all of the examples where
  162.     loops break on '$', 'A', or ' ' because the return from getchar() is
  163.     immediately put into a char variable.
  164.  
  165.     This is a more serious flaw than many, because it results in poorly
  166.     written, inefficient code.
  167.  
  168.     (Couple this with the consistent attempts to use feof() to see if
  169.     the *next* read will fail, when in fact feof() only returns true
  170.     when the *PREVIOUS* read failed, and you get a completely wrong
  171.     description of the standard I/O library.)
  172.  
  173.     Also, several of the programs given loop forever if an end of
  174.     file is reached, because EOF is not checked for in a loop.
  175.  
  176.     Page 284
  177.  
  178.     All of the header files are listed in capitals; the standard
  179.     specifies them in lower case.  It is not required that a
  180.     C compiler reject all-caps, but nor is it required that it
  181.     accept them.
  182.  
  183. Flat contradictions of POSIX, in the discussion of open/read/write.
  184.  
  185.     Page 253
  186.  
  187.         "In most implementations, the operation fails if the file
  188.          specified in the open statement does not exist on the disk."
  189.  
  190.     To the best of my knowledge, POSIX (the standard for the open()
  191.     call) documents and requires the functionality of the O_CREAT flag.
  192.  
  193.     [I spelled that as "C_CREAT" in the original.  Oops. -seebs]
  194.  
  195. Undefined behavior/illegal code.
  196.  
  197.     Page 247
  198.  
  199.     The stream fp is opened with mode "r", the mode to open a text file.
  200.     Then, fseek is called on fp, with the 2nd argument not a value
  201.     returned by a previous call to ftell. (ANSI 7.9.9.2, "For a text
  202.     stream, either offset shall be zero, or offset shall be a value
  203.     returned by an earlier call to the ftell function on the same stream
  204.     and whence shall be SEEK_SET.")
  205.  
  206.     Page 63
  207.  
  208.     If scanf fails, the variable guess is referenced before it has been
  209.     initialized; accessing an uninitialized object introduces
  210.     undefined behavior.
  211.  
  212.     Page 283
  213.  
  214.         >#include <string.h>
  215.         >
  216.         >char s1[] = "hello ";
  217.         >char s2[] = "there.";
  218.         >
  219.         >void main(void)
  220.         >{
  221.         >  int p;
  222.         >
  223.         >  p = strcat(s1, s2);
  224.         >}
  225.  
  226.     It is correctly noted that this generates a warning.  Not mentioned
  227.     is that it's illegal; although s1[] is a modifiable array, it is
  228.     an array large enough to hold "hello " (and the terminating NUL),
  229.     so it has room for 7 bytes.  The strcat overflows the array, producing
  230.     undefined behavior.
  231.  
  232.     Page 735
  233.  
  234.     This is spectacularly wrong; the "corrected"
  235.  
  236.         "x = *p * (*p++);"
  237.  
  238.     is *EXACTLY* equivalent in terms of C; as correctly noted earlier,
  239.     the order of evaluation *IS NOT SPECIFIED*.
  240.  
  241.     The code is still illegal (p is used to determine *p on the left
  242.     of the *, as well as modified on the right), and the parentheses
  243.     aren't affecting the code at all.
  244.  
  245.     In this code, p can be incremented anywhere in the line; the only
  246.     requirement would be that the value of (*p++) be the same as
  247.     the value of (*p) before the increment.  It is *not* specified
  248.     whether the other *p happens before or after the increment.
  249.  
  250.     In fact, because the code modifies an object (p) and uses the value
  251.     of the object to do something other than determine the new value
  252.     (The first "*p"), it is *illegal*.  Completely; a compiler is allowed
  253.     to reject the code, and many will produce surprising results from
  254.     this operation.
  255.  
  256.     This is not merely wrong, it's wrong *while discussing the problem*,
  257.     which is doubly bad.
  258.  
  259. Code which does not do what it says it does.
  260.  
  261.     Page 333
  262.  
  263.         >sprintf("%s %d %c", "one", 2, 3);
  264.  
  265.     The result would be "one 2 " and then a control-c, not "one 2 3".
  266.     (Presumably, "3" should have been "'3'".)
  267.  
  268.     Page 53
  269.  
  270.         >printf("%f", sizeof f);
  271.  
  272.     Clearly wrong; sizeof is not a double or float.
  273.  
  274.     Page 53
  275.  
  276.         >printf("%d", sizeof(int));
  277.  
  278.     Subtly wrong; sizeof is a size_t, which may not be any sort of int.
  279.     The only safe way to do this is
  280.  
  281.         >printf("%ul", (unsigned long) sizeof(int));
  282.  
  283.     While this is larger, a clear explanation of why it is required will
  284.     go a long way towards helping people understand C.
  285.  
  286.     Page 53 (This one's popular)
  287.  
  288.         >/* Write 6 integers to a disk file. */
  289.         >void put_rec(int rec[6], FILE *fp)
  290.         >{
  291.         >  int len;
  292.         >
  293.         >  len = fwrite(rec, sizeof rec, 1, fp);
  294.         >  if (len != 1) printf("write error");
  295.         >}
  296.  
  297.     Incorrect.  As correctly noted elsewhere, when "int rec[6]" is an
  298.     argument to a function, it actually specifies a pointer-to-int,
  299.     not an array[6]-of-int.  sizeof rec is sizeof(int *) here, and this
  300.     code works only if sizeof(int *) is precisely 6 times sizeof(int).
  301.     (Not impossible, but hardly likely.)
  302.  
  303.     Further, who said fp was a disk file?  fp could be stdout.
  304.  
  305. Inaccurate or misleading explanations.
  306.  
  307.     Page 132
  308.  
  309.         "After the assignment, p points to the first 1000 bytes of
  310.          free memory."
  311.  
  312.     No, p points to at least 1000 bytes of allocated space, which is
  313.     not free memory.  There is also no reason to assume it was the
  314.     "first" 1000 bytes; top-down allocation is not atypical, and
  315.     further, there's no reason to assume this code fragment runs in
  316.     isolation.
  317.  
  318.     Page 197
  319.  
  320.     It is redundant to give a size of char in bytes as 1 as an
  321.     "assumption" - it's the definition, sizeof() gives the size
  322.     in *chars*.
  323.  
  324.     Page 162
  325.  
  326.     Functions are not of type void; functions are of various types,
  327.     called collectively the function types.  A function may have a
  328.     return of type void, which means that its type is something like
  329.     "function taking (...) and returning void".
  330.  
  331.     Page 59
  332.  
  333.         "This shorthand works for all the binary operators..."
  334.  
  335.     [Meaning op=, ala +=, -=... -seebs]
  336.     No, it doesn't.  It doesn't work for ".", "->", "&&", or "||".
  337.  
  338.     Page 33
  339.  
  340.         "static Global Variables" [heading]
  341.  
  342.     No such thing.  A static variable outside of a function has file
  343.     scope, which is distinct from global scope.
  344.  
  345. Explanations of a DOS-specific feature as "how C works".
  346.  
  347.     Page 19
  348.  
  349.         "In general, negative numbers are represented using the
  350.          two's complement approach..."
  351.  
  352.     This is not a C feature.  It is a common implementation, but it is
  353.     specifically not required.
  354.  
  355.     Page 131
  356.  
  357.         "Memory allocated by C's dynamic allocation functions is
  358.          obtained from the <i>heap</i> -- the region of free memory
  359.          that lies between your program and its permanent storage
  360.          area and the stack."
  361.  
  362.     C does not specify that there is a stack - only that functions can
  363.     call each other.  The "heap" is a DOS term, and the layout is not
  364.     a part of the C language.  It is not atypical for the layout to be
  365.     radically different, and certainly, there is no call for describing
  366.     a specific choice as "what happens".
  367.  
  368.  
  369. ---cut here
  370.  
  371. *sigh*
  372.  
  373. -seebs
  374. (still hypothetically working on my own reference manual, but the chances
  375. of my getting anywhere until I have enough money and time are quite low.
  376. Donations cheerfully accepted. <- blatant plug!)
  377. -- 
  378. Peter Seebach - seebs@solon.com - Copyright 1995 Peter Seebach.
  379. C/Unix proto-wizard -- C/Unix questions? Send mail for help.  No, really!
  380. Using trn?  Weird new newsgroup problem?  I know the fix!  Email me!
  381. The *other* C FAQ - ftp taniemarie.solon.com /pub/c/afq - Not A Flying Toy
  382.